/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.wendy.common.core.utils.reflect;

import org.springframework.core.DefaultParameterNameDiscoverer;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 跟Method相关的工具类
 *
 * @author Mr.css
 * @version 2021-02-08 11:42
 */
public class MethodUtils {

    private MethodUtils() {
    }

    /**
     * Spring自带的参数提取工具类
     */
    private static final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();

    /**
     * 获取参数名，默认环境下，java反射无法获取参数名，需要这个函数进行辅助
     *
     * @param method 方法
     * @return 参数名
     */
    
    public static String[] getParameterNames(Method method) {
        return discoverer.getParameterNames(method);
    }

    /**
     * 获取参数名，默认环境下，java反射无法获取参数名，需要这个函数进行辅助
     *
     * @param ctor 构造函数
     * @return 参数名
     */
    
    public static String[] getParameterNames(Constructor<?> ctor) {
        return discoverer.getParameterNames(ctor);
    }

    /**
     * 获取 public 修饰的函数，包括父类中存在的函数，如果未找到，不抛出异常，而是返回 null。
     *
     * @param target      对象
     * @param name        函数名
     * @param paramsTypes 参数类型
     * @return method
     */
    
    public static Method getPublicMethod(Class<?> target, String name, Class<?>... paramsTypes) {
        try {
            return target.getMethod(name, paramsTypes);
        } catch (NoSuchMethodException ignore) {
            return null;
        }
    }

    /**
     * 根据字段名，获取对象的getter函数
     *
     * @param fieldName 字段名
     * @param target    对象
     * @return method
     */
    
    public static Method getGetter(Class<?> target, String fieldName) {
        String n = fieldName.substring(0, 1).toUpperCase().concat(fieldName.substring(1));
        String methodName = "get" + n;
        Method method = getPublicMethod(target, methodName);
        if (method == null) {
            // 类似于 disabled 字段，getter 是 isDisabled()
            methodName = "is" + n;
            method = getPublicMethod(target, methodName);
            if (method == null) {
                if (fieldName.startsWith("is")) {
                    // 类似于 isDisabled 字段，getter 是 getDisabled()
                    methodName = "get" + fieldName.substring(2);
                    method = getPublicMethod(target, methodName);
                } else {
                    // 字段名与方法名相同，不符合规范，但是可能存在这种奇葩的设计
                    method = getPublicMethod(target, fieldName);
                }
            }
        }
        return method;
    }

    /**
     * 根据字段名，获取对象的setter函数
     *
     * @param target    对象
     * @param fieldName 字段名
     * @param type      参数类型
     * @return method
     */
    
    public static Method getSetter(Class<?> target, String fieldName, Class<?> type) {
        String n = fieldName.substring(0, 1).toUpperCase().concat(fieldName.substring(1));
        String methodName = "set" + n;
        Method method = getPublicMethod(target, methodName, type);
        if (method == null) {
            // 类似于isDisabled字段，setter是setDisabled
            if (fieldName.startsWith("is")) {
                methodName = "set" + fieldName.substring(2);
                method = getPublicMethod(target, methodName, type);
            } else {
                // 字段名与方法名相同，不符合规范，但是可能存在这种奇葩的设计
                method = getPublicMethod(target, fieldName, type);
            }
        }
        return method;
    }
}
